/* dtrain.c
 *	Client user program of distributed ticket checker in a train simulation
 *	
 *	Simulates a Train
 */
 
#include "syscall.h"

const int MAXSTOPS = 10; /*How many Stops*/
const int MAXPASSENGERS = 30; /*Maximum Passengers*/
const int NUMBER_OF_COACHATTENDANTS = 3; /*How many Coach Attendant on the Train*/
const int NUMBER_OF_PORTERS = 3; /*How many Porters on the Train*/

int nextStopLock;
int nextStop;
int currentStop;
int numFirstClassThatBoarded;
int numEconClassThatBoarded;
int attendantBroadcast;
int porterBroadcast; 
int tcTrainWaiting;
int getOnStop[40]; /* stop to get on at*/
int getOffStop[40]; /*stop to get off at*/
int waitingToBeSatLineLength[3];
int coachAttendantBusy[3];
int g_seatingPsgNumber[3];
int seatAssignment[3];
int porterLineLength[3];
int passengerBeingHelped[3];
int seats[100];/* true if seat is occupied 40*3*/
int porterAvailable[3];

void Train(void);
void Dummy(void);
void setupMonitors(void);
void itoa(char arr[], int size, int val);

int main(int argc, char **argv)
{
	void (*myTrain)(void);
	void (*myDummy)(void); /*For some reason if you fork just once, nothing works*/
	
	myTrain = &Train;
	myDummy = &Dummy;
	
	setupMonitors(); /*Requesting all the locks, CVs, and MVs needed by Ticket Checker client*/
	Fork(myTrain);
	Fork(myDummy);

	Exit(0);
}

void Dummy()
{
	PrintOut("Dummy Thread\n", 13);
    Exit(0);		
}

/*Requesting all the locks, CVs, and MVs needed by Train client*/
void setupMonitors()
{ 
	int i;
	char indexBuf[2];
	char nameBuf[4]; /*a prefix will be put in first two slots, then the local index*/
	
	for (i = 0; i < NUMBER_OF_COACHATTENDANTS; i ++){
		itoa (indexBuf, 2, i);
		nameBuf[0] = 'c';
		nameBuf[1] = 'v';
		nameBuf[2] = indexBuf[0];
		nameBuf[3] = indexBuf[1]; /* Example name: "cv2"*/
		waitingToBeSatLineLength[i] = CreateMV(nameBuf, 4, 1);
		SetMV(waitingToBeSatLineLength[i], 0);
		nameBuf[0] = 'c';
		nameBuf[1] = 'b'; /* CA Busy */
		coachAttendantBusy[i] = CreateMV(nameBuf, 4, 1);
		SetMV(coachAttendantBusy[i], 0);
		nameBuf[0] = 's';
		nameBuf[1] = 'n'; /* Seat Number */
		g_seatingPsgNumber[i] = CreateMV(nameBuf, 4, 1);
		SetMV(g_seatingPsgNumber[i], 0);
		nameBuf[0] = 's';
		nameBuf[1] = 'a'; /* Seat Assignment */
		seatAssignment[i] = CreateMV(nameBuf, 4, 1);
		SetMV(seatAssignment[i], 999); 
	}
	
	for(i=0; i<3*MAXPASSENGERS; i++){
		itoa (indexBuf, 2, i);
		nameBuf[0] = 's';
		nameBuf[1] = 't';
		nameBuf[2] = indexBuf[0];
		nameBuf[3] = indexBuf[1]; /* Example name: "st2"*/
		seats[i] = CreateMV(nameBuf, 4, 1);
		SetMV(seats[i], 0);
	}
	
	for(i=0; i<NUMBER_OF_PORTERS; i++){
		itoa (indexBuf, 2, i);
		nameBuf[0] = 'p';
		nameBuf[1] = 'l';
		nameBuf[2] = indexBuf[0];
		nameBuf[3] = indexBuf[1]; /* Example name: "pt2"*/
		porterLineLength[i] = CreateMV(nameBuf, 4, 1);
		SetMV(porterLineLength[i], 0);
		nameBuf[0] = 'p';
		nameBuf[1] = 'a'; /* Porter Avaliable */
		porterAvailable[i] = CreateMV(nameBuf, 4, 1);
		SetMV(porterAvailable[i], 1);
		nameBuf[0] = 'p';
		nameBuf[1] = 'h'; /* Psg Helped */
		passengerBeingHelped[i] =CreateMV(nameBuf, 4, 1);
		SetMV(passengerBeingHelped[i], 999);
	}
	
	/*Locks*/
	nextStopLock = CreateLock("nextStopLock", 12, 1);
	
	/*CVs*/
	nextStop = CreateCV("nextStopCV", 10, 1);

	/*MVs*/
	currentStop = CreateMV("currentStopMV", 13, 1); 
	numFirstClassThatBoarded = CreateMV("nFClassThatBoarded", 18, 1);

	numEconClassThatBoarded = CreateMV("nECThatBoardedMV", 16, 1);

	attendantBroadcast = CreateMV("attBroadcastMV", 14, 1);
	porterBroadcast = CreateMV("porterBroadcastMV", 17, 1);
	/*--Ticket Checker waiting on Train--*/
	tcTrainWaiting = CreateMV("tcTrainWaitingMV", 16, 1);
}

void Train()
{
	int lastStop = -1;
	int randomNum;
	int i;
	char buf[2];
	char nowStop [2];
	int currentS, tcTrainW;

	while (GetMV(currentStop)< MAXSTOPS)
    {
		currentS = GetMV(currentStop);

		if(lastStop < currentS)
		{
			/*First enter monitor for arriving at next stop*/
			PrintOut("We are at: ", 11);
			itoa (nowStop, 2, currentS);
			PrintOut(nowStop ,2);
			PrintOut(" \n",2);
			
			Acquire(nextStopLock,0);
			tcTrainW = GetMV(tcTrainWaiting);
			while (tcTrainW == 0){
			}
			/*PrintOut("2 TA HERE!!\n", 12);*/
			SetMV(tcTrainWaiting, 0);
			/*Signal to ticket checker at this stop that he can begin*/
			Signal(nextStop, nextStopLock,0);
			/*Exiting monitor*/
			Release(nextStopLock,0);
			/*Resetting various variables used in the boarding/seating process*/
			SetMV(numFirstClassThatBoarded, 0);
			SetMV(numEconClassThatBoarded, 0);
			SetMV(attendantBroadcast, 0);
			SetMV(porterBroadcast, 0);

			lastStop = GetMV(currentStop);
		}

		/*Generating a random number that ranges from [25,50]*/
		randomNum=((5*RandomInt())%25)*1000;
		if(randomNum<0)
			randomNum=randomNum*-1 +25;
		else
			randomNum+=25;
		/*Yielding currentThread that many times to give enough time for things to happen between stops*/
		for (i= 0; i< randomNum; i++)
			Yield(0);
		SetMV(currentStop, GetMV(currentStop) + 1);	
	 }
	Exit(0);
}
/* ********End Train****************************/

int myexp ( int count ) {
  int i, val=1;
  for (i=0; i<count; i++ ) {
    val = val * 10;
  }
  return val;
}

void itoa( char arr[], int size, int val ) {
  int i, max, dig, subval, loc;
  for (i=0; i<size; i++ ) {
    arr[i] = '\0';
  }

  for ( i=1; i<=10; i++ ) {
    if (( val / myexp(i) ) == 0 ) {
      max = i-1;
      break;
    }
  }

  subval = 0;
  loc = 0;
  for ( i=max; i>=0; i-- ) {
    dig = 48 + ((val-subval) / myexp(i));
    subval += (dig-48) * myexp(i);
    arr[loc] = dig;
    loc++;
  }

  return;
}